{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 346,
   "id": "0b1b34d2",
   "metadata": {},
   "outputs": [],
   "source": [
    "from urllib.parse import urlparse\n",
    "from urllib import parse\n",
    "import cv2\n",
    "import requests\n",
    "from pyzbar.pyzbar import decode\n",
    "import matplotlib.pyplot as plt\n",
    "from datetime import datetime\n",
    "import random\n",
    "import time\n",
    "import re\n",
    "\n",
    "class AutoSign:\n",
    "    \n",
    "    def __init__(self):\n",
    "        \n",
    "        self.user_info_url = \"https://sso.chaoxing.com/apis/login/userLogin4Uname.do\"\n",
    "        self.login_url = \"https://passport2-api.chaoxing.com/v11/loginregister?code=22446688a&cx_xxt_passport=json&uname=17394975679&loginType=1&roleSelect=true\"\n",
    "        self.user_class_url = \"http://mooc1-api.chaoxing.com/mycourse/backclazzdata?view=json&rss=1\"\n",
    "        self.pre_sign_url = \"https://mobilelearn.chaoxing.com/newsign/preSign?courseId={}&classId={}&activePrimaryId={}&general=1&sys=1&ls=1&appType=15&tid=&uid={}&ut=s\"\n",
    "        self.user_act_url = \"https://mobilelearn.chaoxing.com/v2/apis/active/student/activelist?fid=0&courseId={}&classId={}&showNotStartedActive=0&_=1663752482576\"\n",
    "        self.sign_url = \"https://mobilelearn.chaoxing.com/pptSign/stuSignajax?activeId={}&enc={}&fid=0\"\n",
    "        self.headers = {}\n",
    "        self.info = None\n",
    "        self.cls_list = None\n",
    "        self.uid = None\n",
    "        self.fid = None\n",
    "        self.cookies = None\n",
    "        \n",
    "        self.set_login_cookies()\n",
    "        self.set_header()\n",
    "        self.set_base_info()\n",
    "        \n",
    "    # 设置请求头\n",
    "        \n",
    "    def set_header(self):\n",
    "        user_agent_list = [\n",
    "            \"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36\",\n",
    "            \"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36\",\n",
    "            \"Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/61.0\",\n",
    "            \"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36\",\n",
    "            \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36\",\n",
    "            \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36\",\n",
    "            \"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)\",\n",
    "            \"Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15\",\n",
    "            ]\n",
    "        self.headers['User-Agent'] = random.choice(user_agent_list)\n",
    "\n",
    "\n",
    "\n",
    "    # 登录并获取cookies\n",
    "    def set_login_cookies(self):\n",
    "        login = requests.post(login_url)\n",
    "        self.cookies = requests.utils.dict_from_cookiejar(login.cookies)\n",
    "\n",
    "    # 设置个人信息\n",
    "    def set_base_info(self):\n",
    "        self.info = requests.get(self.user_info_url, cookies=self.cookies)\n",
    "        cls = requests.get(self.user_class_url, cookies=self.cookies, headers=self.headers)\n",
    "        self.cls_list = cls.json()['channelList']\n",
    "        self.fid = self.info.json()['msg']['fid']\n",
    "        self.uid = self.info.json()['msg']['uid']\n",
    "\n",
    "    def get_class_info_by_index(self, index):\n",
    "        cour_id = self.cls_list[index]['content']['course']['data'][0]['id']\n",
    "        cls_id = self.cls_list[index]['content']['id']\n",
    "        return [cour_id, cls_id]\n",
    "\n",
    "    def get_class_info_by_name(self, name):\n",
    "        is_find = False\n",
    "        pattern = f'.*{name}.*'\n",
    "        for i in range(len(cls_list)):\n",
    "            cls_name = cls_list[i]['content']['course']['data'][0]['name']\n",
    "            if re.match(pattern, cls_name) is not None:\n",
    "                cour_id = cls_list[i]['content']['course']['data'][0]['id']\n",
    "                cls_id = cls_list[i]['content']['id']\n",
    "                print(cls_name)\n",
    "                print(f\"index:{i}\")\n",
    "                return [cour_id, cls_id]\n",
    "        print(\"未找到课程\")\n",
    "        return None\n",
    "    \n",
    "    # 获取活动信息\n",
    "\n",
    "    def get_act_by_name(self, name):\n",
    "        cour_id,cls_id = get_class_info_by_name(name)\n",
    "        return get_act_by_id(cour_id, cls_id)['data']['activeList']\n",
    "\n",
    "\n",
    "    def get_act_by_id(cour_id, cls_id):\n",
    "        user_act = requests.get(self.user_act_url.format(cour_id, cls_id), headers=self.headers, cookies=self.cookies)\n",
    "        return user_act.json()\n",
    "\n",
    "\n",
    "    # 寻找需要签到的活动\n",
    "\n",
    "    def find_unsign_act(self):\n",
    "        for i in range(len(self.cls_list)):\n",
    "            cour_id, cls_id = get_class_info_by_index(i)\n",
    "            cls_name = self.cls_list[i]['content']['course']['data'][0]['name']\n",
    "            # 获取当前课程最近一次的签到信息\n",
    "            act_data_list = get_act_by_id(cour_id, cls_id)['data']['activeList']\n",
    "            if(len(act_data_list) > 0):\n",
    "                act_data = act_data_list[0]\n",
    "            else:\n",
    "                continue\n",
    "            act_id = act_data['id']\n",
    "            # 找到没签到的课程,回传课程ID和活动ID\n",
    "            # 查找10s内的签到\n",
    "            if(int(act_data['activeType']) == 2 and int(act_data['status']) == 1 and int(act_data['startTime'] + 10000 >= int(time.time() * 1000))):\n",
    "                print(cls_name)\n",
    "                return [cour_id, cls_id, act_id]\n",
    "        print(\"没有新的签到\")\n",
    "        return False\n",
    "    \n",
    "    # 预签到\n",
    "\n",
    "    def act_pre_sign(cour_id, cls_id, act_id):\n",
    "        requests.get(pre_sign_url.format(cour_id, cls_id ,act_id, self.uid) , cookies=self.cookies)\n",
    "    \n",
    "    # 二维码签到\n",
    "    \n",
    "    def sign_in_by_QR(cour_id, cls_id, act_id ,enc):\n",
    "        act_pre_sign(cour_id, cls_id, act_id, self.uid)\n",
    "        sign = requests.get(sign_url.format(act_id, enc) , cookies=self.cookies)\n",
    "        return sign.json()\n",
    "    \n",
    "    def upload_and_decode_QR(self, img_path):\n",
    "        path = img_path\n",
    "        img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)\n",
    "        ret, img = cv2.threshold(img, 200, 255,cv2.THRESH_BINARY)\n",
    "        res = decode(img)\n",
    "        if len(res) > 0:\n",
    "            data = str(res[0].data, encoding='utf-8')\n",
    "            return data\n",
    "        else:\n",
    "            print(\"二维码解析失败\")\n",
    "            data = None\n",
    "    def splite_QR_content(self, img_path):\n",
    "        content = upload_and_decode_QR(img_path)\n",
    "        if content is not None:\n",
    "            res = urlparse(content)\n",
    "            enc = parse.parse_qs(res.query)['enc'][0]\n",
    "            return enc\n",
    "        return None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 323,
   "id": "0fb2590f",
   "metadata": {},
   "outputs": [],
   "source": [
    "as1 = AutoSign()\n",
    "as1.find_unsign_act()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
